﻿using System;

namespace Microsoft.CSA.FeedSync.FeedSyncLibrarySL
{
    public class History
    {
        private System.Xml.Linq.XElement m_XElement;

        private System.DateTime? m_WhenDateTime;

        private string m_By;

        private uint m_Sequence;

        private Microsoft.CSA.FeedSync.FeedSyncLibrarySL.Sync m_Sync;

        public History(System.Xml.Linq.XElement i_HistoryXElement)
        {
            if (i_HistoryXElement == null)
                throw new System.ArgumentException("i_HistoryXElement must be non-null!");

            bool InvalidXElement =
                (i_HistoryXElement.Name.LocalName != Microsoft.CSA.FeedSync.FeedSyncLibrarySL.Constants.HISTORY_ELEMENT_NAME) ||
                (i_HistoryXElement.Name.NamespaceName != Microsoft.CSA.FeedSync.FeedSyncLibrarySL.Constants.FEEDSYNC_XML_NAMESPACE_URI);

            if (InvalidXElement)
                throw new System.Exception("Invalid i_HistoryXElement!");

            m_XElement = i_HistoryXElement;

            m_Sequence = System.Convert.ToUInt32(i_HistoryXElement.Attribute(Microsoft.CSA.FeedSync.FeedSyncLibrarySL.Constants.SEQUENCE_ATTRIBUTE).Value);

            if (i_HistoryXElement.Attribute(Microsoft.CSA.FeedSync.FeedSyncLibrarySL.Constants.WHEN_ATTRIBUTE) != null)
            {
                string When = i_HistoryXElement.Attribute(Microsoft.CSA.FeedSync.FeedSyncLibrarySL.Constants.WHEN_ATTRIBUTE).Value;
                m_WhenDateTime = System.Convert.ToDateTime(When).ToUniversalTime();
            }

            if (i_HistoryXElement.Attribute(Microsoft.CSA.FeedSync.FeedSyncLibrarySL.Constants.BY_ATTRIBUTE) != null)
                m_By = i_HistoryXElement.Attribute(Microsoft.CSA.FeedSync.FeedSyncLibrarySL.Constants.BY_ATTRIBUTE).Value;

            this.Validate();
        }

        public History(Microsoft.CSA.FeedSync.FeedSyncLibrarySL.Sync i_Sync, uint i_Sequence, System.DateTime? i_WhenDateTime, string i_By)
        {
            m_Sequence = i_Sequence;
            m_By = i_By;

            if (i_WhenDateTime.HasValue)
                m_WhenDateTime = ((System.DateTime)i_WhenDateTime).ToUniversalTime();

            m_XElement = new System.Xml.Linq.XElement(Microsoft.CSA.FeedSync.FeedSyncLibrarySL.Constants.FeedSyncXNamespace + Microsoft.CSA.FeedSync.FeedSyncLibrarySL.Constants.HISTORY_ELEMENT_NAME);

            m_XElement.SetAttributeValue(Microsoft.CSA.FeedSync.FeedSyncLibrarySL.Constants.SEQUENCE_ATTRIBUTE, m_Sequence.ToString());

            if (!System.String.IsNullOrEmpty(m_By))
                m_XElement.SetAttributeValue(Microsoft.CSA.FeedSync.FeedSyncLibrarySL.Constants.BY_ATTRIBUTE, m_By);

            if (m_WhenDateTime.HasValue)
                m_XElement.SetAttributeValue(Microsoft.CSA.FeedSync.FeedSyncLibrarySL.Constants.WHEN_ATTRIBUTE, ((System.DateTime)m_WhenDateTime).ToString(Microsoft.CSA.FeedSync.FeedSyncLibrarySL.Constants.DATE_STRING_FORMAT));

            this.Validate();
        }

        private void Validate()
        {
            if ((m_WhenDateTime == null) && (System.String.IsNullOrEmpty(m_By)))
                throw new System.ArgumentException("Must have 'when' or 'by' attribute!");

            if (m_Sequence > (System.Math.Pow(2, 32) - 1))
                throw new System.ArgumentException("Invalid value for 'sequence' attribute!");
        }

        public System.DateTime? WhenDateTime
        {
            get
            {
                return m_WhenDateTime;
            }
        }

        public string By
        {
            get
            {
                return m_By;
            }
        }

        public uint Sequence
        {
            get
            {
                return m_Sequence;
            }
            internal set
            {
                if (value <= m_Sequence)
                    throw new System.ArgumentException("Value must be greater than current Sequence!");

                m_XElement.SetAttributeValue(Microsoft.CSA.FeedSync.FeedSyncLibrarySL.Constants.SEQUENCE_ATTRIBUTE, m_Sequence.ToString());
            }
        }

        public Microsoft.CSA.FeedSync.FeedSyncLibrarySL.Sync Sync
        {
            get
            {
                return m_Sync;
            }
            internal set
            {
                if (value == null)
                    throw new System.ArgumentException("Value must be non-null!");

                m_Sync = value;
            }
        }

        public System.Xml.Linq.XElement XElement
        {
            get
            {
                return m_XElement;
            }
        }

        public bool IsSubsumedBy(Microsoft.CSA.FeedSync.FeedSyncLibrarySL.History i_History)
        {
            bool Subsumed = false;

            if (!System.String.IsNullOrEmpty(m_By))
            {
                Subsumed =
                    (m_By == i_History.By) &&
                    (i_History.Sequence >= m_Sequence);
            }
            else
            {
                Subsumed =
                    (m_WhenDateTime == i_History.WhenDateTime) &&
                    (m_Sequence == i_History.Sequence);
            }

            return Subsumed;
        }
    }
}
